<template>
    <div>
        <h1>子组件演示</h1>
        <button @click="updateData">子组件点击</button>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const sonData = ref<string>('子组件数据');

const sonMethod = (type: number, data?: string): string => {
    console.log('子组件方法调用');
    return `子组件方法返回值: ${type} - ${data}`;
};

// 1.不约定类型
// const emit = defineEmits(['updateSonData']);

// 2.泛型形式声明
// const emit = defineEmits<{
//     (event: 'update1', data: string): void, // 约定update1事件的类型
//     (e: 'update2', data: {name: string, age: number}): void, // 约定update2事件的类型
// }>();

// 3.对象形式声明（带验证）
const emit = defineEmits({
    update1: (data: string) => data.length <= 5, // 约定update1事件的类型, 必须是string类型且长度小于等于5
    update2: (data: { name: string; age: number }) => true // 约定update2事件的类型, 必须是{name: string, age: number}格式
});
const updateData = () => {
    emit('update1', '这是子组件的update3事件数据'); // 长度大于5不报错,浏览器会警告
};

// 4.通过接口约定事件类型(无法带验证)
// interface UpdateSonDataEvent {
//     (event: 'update1', data: string): void;
//     (event: 'update2', data: { name: string; age: number }): void;
// }
// // UpdateSonDataEvent类型可以直接用在defineEmits中
// const emit = defineEmits<UpdateSonDataEvent>();
// const updateData = () => {
//     emit('update1', '这是子组件的update3事件数据');
// };

defineExpose({
    sonData, // 暴露子组件数据给父组件
    sonMethod // 暴露子组件方法给父组件
});
</script>

<style scoped></style>
